#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <string>
#include <atomic>
#include <thread>
#include <vector>

template <typename T>
void is_atomic(const T& val)
{
	std::cout << std::is_trivially_copyable<T>::value << std::endl;
	std::cout << std::is_copy_constructible<T>::value << std::endl;
	std::cout << std::is_move_constructible<T>::value << std::endl;
	std::cout << std::is_copy_assignable<T>::value << std::endl;
	std::cout << std::is_move_assignable<T>::value << std::endl;
	std::cout << std::is_same<T, typename std::remove_cv<T>::type>::value << std::endl;

}

class Date
{
public:
	int _a;
	int _b;
	int _c;
};

//int main()
//{
//	std::cout << "int" << std::endl;
//	is_atomic(1);
//
//	int a = 0;
//	std::cout << "int*" << std::endl;
//	is_atomic(&a);
//
//	std::cout << "string" << std::endl;
//	is_atomic(std::string("11"));
//
//	std::string s = "124l";
//	std::cout << "string*" << std::endl;
//	is_atomic(&s);
//
//
//	std::cout << "Date" << std::endl;
//	is_atomic(Date());
//
//	return 0;
//}


//int main()
//{
//	std::atomic<int> a = 0;
//
//	// 读取操作
//	std::cout << a.load() << std::endl;
//
//	// 存储操作
//	a.store(100);
//	std::cout << a.load() << std::endl;
//
//	// 交换操作
//	// 原子的将底层存储的数据改变为目标值，并且返回交换之前的值
//	std::cout << a.exchange(200) << std::endl;
//	std::cout << a.load() << std::endl;
//
//	return 0;
//}


std::atomic<int> cnt1 = 0;
int cnt2 = 0;

void atomic_add(std::atomic<int>& cnt)
{
	// 1.先获取当前值
	int old = cnt;

	// 2.利用CAS操作，对变量进行修改
	while (!std::atomic_compare_exchange_weak(&cnt, &old, old + 1));
}

void f()
{
	for (int i = 0; i < 1000000; i++) {
		// 利用atomic的operator++实现原子操作
		cnt1++;

		// 利用CAS操作，模拟atomic的operator++原子操作
		// atomic_add(cnt1);

		cnt2++;
	}
}

int main()
{
	std::vector<std::thread> threads;
	for (int i = 0; i < 4; i++) {
		threads.emplace_back(f);
	}

	for (auto& t : threads) {
		t.join();
	}

	std::cout << cnt1 << std::endl;
	std::cout << cnt2 << std::endl;
	return 0;
}